home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998…eptember: Technology Seed / September 98 ADC Seed CD.toast / Language Analysis Manager / DarumaDR1Package / Examples / TextConverter / Sources / HighLevelTextConvert.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-27  |  13.7 KB  |  433 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        HighLevelTextConvert.c
  3.     
  4.     Contains:    A Sample application for High-level text conversion
  5.  
  6.      Version:    Technology:    System 8
  7.                  Release:    Daruma Developer Release 1
  8.  
  9.      Copyright:    1998 by Apple Computer, Inc., all rights reserved
  10.  
  11.      Contact:    daruma@apple.com
  12.  
  13. */
  14.  
  15.  
  16. #include "HighLevelTextConvert.h"
  17. #include "DebugUtil.h"
  18.  
  19. #include <LanguageAnalysis.h>
  20. #include <JapaneseAnalysisEngine.h>
  21.  
  22.  
  23. //========================================================================================
  24. // Global variables
  25. //========================================================================================
  26. static LAContextRef    gLastUsedContext = NULL;
  27.  
  28. //========================================================================================
  29. // Prototypes for static functions
  30. //========================================================================================
  31. static OSStatus ConvertTextCommon( UInt16 conversionType, ByteCount inLength, const char *inTextBuf, ByteCount maxLength, ByteCount *outLength, char *outTextBuf );
  32. static OSStatus PrepareAnalysisContext( UInt16 conversionType, LAContextRef *context );
  33. static OSStatus InterpretBundleAsText( LAMorphemeBundle *bundle, ByteCount maxLength, ByteCount *outLength, void *outTextBuf );
  34. static OSStatus MapErrorCode( OSStatus originalError );
  35.  
  36.  
  37. /* =======================================================================================
  38.     Routine:    LaConvertPascalString (exported interface)
  39.     
  40.     Purpose:    Convert specified pascal string
  41.     
  42.     Params:        conversionType (in)        : types of source text and destination
  43.                 inStr (in)                : source pascal string
  44.                 outLength (out)            : actual length of converted text
  45.                 outStr (out)            : allocated buffer for converted pascal string
  46.    ======================================================================================= */
  47. OSStatus
  48. LaConvertPascalString( UInt16 conversionType, ConstStr255Param inStr,
  49.                        ByteCount *outLength, Str255 outStr)
  50. {
  51.     OSStatus        err;
  52.     
  53.     err = ConvertTextCommon( conversionType, inStr[0], (char *)&inStr[1], 255, outLength, (char *)&outStr[1]);
  54.     nrequire( err, convert_Failure);
  55.     
  56.     outStr[0] = ( *outLength > 255 ? 255 : (unsigned char)*outLength);
  57.     
  58.     return noErr;
  59.  
  60. //'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  61. convert_Failure:
  62.     return MapErrorCode( err);
  63. }
  64.  
  65.  
  66. /* =======================================================================================
  67.     Routine:    LaConvertText (exported interface)
  68.     
  69.     Purpose:    Convert specified text
  70.     
  71.     Params:        conversionType (in)        : types of source text and destination
  72.                 inLength (in)            : length of source text
  73.                 inTextBuf (in)            : buffer of source text
  74.                 maxLength (in)            : size of allocated buffer for output
  75.                 outLength (out)            : actual length of converted text
  76.                 outTextBuf (out)        : allocated buffer for converted text
  77.    ======================================================================================= */
  78. OSStatus
  79. LaConvertText( UInt16 conversionType, ByteCount inLength, const char *inTextBuf,
  80.                ByteCount maxLength, ByteCount *outLength, char *outTextBuf )
  81. {
  82.     OSStatus    err;
  83.     
  84.     err = ConvertTextCommon( conversionType, inLength, inTextBuf, maxLength, outLength, outTextBuf);
  85.     nrequire( err, convert_Failure);
  86.     
  87.     return noErr;
  88.  
  89. //'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  90. convert_Failure:
  91.     return MapErrorCode( err);
  92. }
  93.  
  94.  
  95. /* =======================================================================================
  96.     Routine:    LaFinalizeConvert (exported interface)
  97.     
  98.     Purpose:    Cleanup context
  99.     
  100.     Params:        none
  101.    ======================================================================================= */
  102. void
  103. LaFinalizeConvert( void)
  104. {
  105.     if ( gLastUsedContext != NULL)
  106.         LACloseContext( gLastUsedContext);
  107. }
  108.  
  109.  
  110. /* =======================================================================================
  111.     Routine:    ConvertTextCommon
  112.     
  113.     Purpose:    Convert specified text
  114.     
  115.     Params:        conversionType (in)        : types of source text and destination
  116.                 inLength (in)            : length of source text
  117.                 inTextBuf (in)            : buffer of source text
  118.                 maxLength (in)            : size of allocated buffer for output
  119.                 outLength (out)            : actual length of converted text
  120.                 outTextBuf (out)        : allocated buffer for converted text
  121.    ======================================================================================= */
  122. static OSStatus
  123. ConvertTextCommon( UInt16 conversionType, ByteCount inLength, const char *inTextBuf,
  124.                    ByteCount maxLength, ByteCount *outLength, char *outTextBuf )
  125. {
  126.     OSStatus            err;
  127.     LAContextRef        context;
  128.     LAMorphemePath        *leadingEdge, *trailingEdge;
  129.     LAMorphemeBundle    analysisResult;
  130.     
  131.     require_action( inLength <= 255, tooLongText_Failure, err = kConvTextOverFlowErr;);
  132.     
  133.     err = PrepareAnalysisContext( conversionType, &context);
  134.     nrequire( err, getContext_Failure);
  135.     
  136.     //------------------------------------------------------------
  137.     // Batch analysis
  138.     //
  139.     leadingEdge  = (LAMorphemePath *)kLADefaultEdge;
  140.     trailingEdge = (LAMorphemePath *)kLADefaultEdge;
  141.     
  142.     err = LAMorphemeAnalysis( context, inTextBuf, inLength, leadingEdge, trailingEdge, 1, &analysisResult);
  143.     nrequire( err, batchAnalysis_Failure);
  144.     
  145.     //------------------------------------------------------------
  146.     // Get converted text
  147.     //
  148.     err = InterpretBundleAsText( &analysisResult, maxLength, outLength, outTextBuf);
  149.     nrequire( err, getTextFromBundle_failure);
  150.     
  151.     //------------------------------------------------------------
  152.     // Clean up
  153.     //
  154.     AEDisposeDesc( &analysisResult);
  155.     
  156.     return noErr;
  157.     
  158. //'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  159. getTextFromBundle_failure:
  160.     AEDisposeDesc( &analysisResult);
  161. batchAnalysis_Failure:
  162. getContext_Failure:
  163. tooLongText_Failure:
  164.     return err;
  165. }
  166.  
  167.  
  168. /* =======================================================================================
  169.     Routine:    PrepareAnalysisContext
  170.     
  171.     Purpose:    If specified context is already opened, just returns it.
  172.                 If not, open a new context and returns it.
  173.     
  174.     Params:        conversionType (in)        : types of source text and destination
  175.                 context (out)            : Daruma analysis context
  176.    ======================================================================================= */
  177. static OSStatus
  178. PrepareAnalysisContext( UInt16 conversionType, LAContextRef *context )
  179. {
  180.     static UInt16        gLastUsedConversionType = 0;
  181.     OSStatus            err, specificErr;
  182.     LAEnvironmentRef    environment;
  183.     Str63                environmentName[3] = { kLAJapaneseKanaKanjiEnvironment,
  184.                                                kLAJapaneseMorphemeAnalysisEnvironment,
  185.                                                kLAJapaneseTTSEnvironment };
  186.  
  187.     //------------------------------------------------------------
  188.     // Prepare analysis context if it is not opened yet.
  189.     // (Last used context is cached)
  190.     //
  191.     if ( gLastUsedConversionType != conversionType)
  192.     {
  193.         switch ( conversionType)
  194.         {
  195.         case kConvertKanaToKanji:
  196.             err = LAGetEnvironmentRef( environmentName[0], &environment);
  197.             break;
  198.         
  199.         case kConvertKanjiToKana:
  200.             err = LAGetEnvironmentRef( environmentName[1], &environment);
  201.             break;
  202.         
  203.         case kConvertKanjiToUtterance:
  204.             err = LAGetEnvironmentRef( environmentName[2], &environment);
  205.             break;
  206.         
  207.         default:
  208.             require_action( false, unknownType_failure, err = kConvUnknownConversionTypeErr;);
  209.             break;    
  210.         }
  211.         nrequire( err, getEnvironmentRef_Failure);
  212.         
  213.         //
  214.         // Close old context (only one context is opened at a time)
  215.         //
  216.         if ( gLastUsedContext != NULL)
  217.         {
  218.             LACloseContext( gLastUsedContext);
  219.             gLastUsedContext = NULL;
  220.         }
  221.         
  222.         err = LAOpenContext( environment, &gLastUsedContext, &specificErr, NULL);
  223.         nrequire( err, openContext_Failure);
  224.  
  225.         gLastUsedConversionType = conversionType;
  226.     }
  227.     
  228.     *context = gLastUsedContext;
  229.     
  230.     return noErr;
  231.     
  232. //'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  233. openContext_Failure:
  234.     gLastUsedConversionType = 0;
  235.     *context = NULL;
  236. getEnvironmentRef_Failure:
  237. unknownType_failure:
  238.     return err;    
  239. }
  240.  
  241.  
  242. /* =======================================================================================
  243.     Routine:    InterpretBundleAsText
  244.     
  245.     Purpose:    Gather converted text chunk in AERecord, and merge them into continuous text
  246.     
  247.     Params:        bundle (in)                : result AERecord returned by morpheme analysis
  248.                 maxLength (in)            : size of allocated buffer for output
  249.                 outLength (out)            : actual length of converted text
  250.                 outTextBuf (out)        : allocated buffer for converted text
  251.    ======================================================================================= */
  252. static OSStatus
  253. InterpretBundleAsText( LAMorphemeBundle *bundle, ByteCount maxLength,
  254.                        ByteCount *outLength, void *outTextBuf )
  255. {
  256.     OSStatus            err;
  257.     long                i, morphemeIndex;
  258.     long                morphemeNum;
  259.     AEDescList            morphemeNodeList    = { typeNull, NULL};
  260.     AEDescList            morphemePathList    = { typeNull, NULL};
  261.     AEDescList            morphemeIndexList    = { typeNull, NULL};
  262.     AERecord            morphemePath        = { typeNull, NULL};
  263.     AERecord            morpheme            = { typeNull, NULL};
  264.     AEDescList            homographList        = { typeNull, NULL};
  265.     AERecord            homograph            = { typeNull, NULL};
  266.     AEKeyword            theAEKeyword;
  267.     DescType            typeCode;
  268.     long                actualSize;
  269.     char                *outTextPtr = (char *)outTextBuf;
  270.     ByteCount            totalLength = 0;
  271.     Boolean                hasOverflow = false;
  272.     
  273.     //------------------------------------------------------------
  274.     // Get morpheme node list
  275.     //
  276.     err = AEGetKeyDesc( bundle, keyAELAMorpheme, typeAEList, &morphemeNodeList);
  277.     nrequire( err, getMorphemeNodeList_failure);
  278.     
  279.     //------------------------------------------------------------------------------
  280.     // Get morpheme path list
  281.     //
  282.     err = AEGetKeyDesc( bundle, keyAELAMorphemePath, typeAEList, &morphemePathList);
  283.     nrequire( err, getMorphemePathList_failure);
  284.  
  285.     //------------------------------------------------------------
  286.     // Get 1st morpheme path from morpheme path list
  287.     //
  288.     err = AEGetNthDesc( &morphemePathList, 1, typeAERecord, &theAEKeyword, &morphemePath);
  289.     AEDisposeDesc( &morphemePathList);
  290.     nrequire( err, getMorphemePath_failure);
  291.         
  292.     //------------------------------------------------------------
  293.     // Get morpheme index list from morpheme path
  294.     //
  295.     err = AEGetKeyDesc( &morphemePath, keyAELAMorpheme, typeAEList, &morphemeIndexList);
  296.     AEDisposeDesc( &morphemePath);
  297.     nrequire( err, getMorphemeIndexList_failure);
  298.  
  299.     //------------------------------------------------------------
  300.     // Count morpheme in the list
  301.     //
  302.     err = AECountItems( &morphemeIndexList, &morphemeNum);
  303.     nrequire( err, countMorphemeNum_Failure);
  304.  
  305.     for ( i = 1; i <= morphemeNum; i++)
  306.     {
  307.         //------------------------------------------------------------
  308.         // Get ith morpheme index from morpheme index list
  309.         //
  310.         err = AEGetNthPtr( &morphemeIndexList, i, typeInteger, &theAEKeyword, &typeCode,
  311.                            &morphemeIndex, sizeof(morphemeIndex), &actualSize);
  312.         nrequire( err, getMorphemeIndex_Failure);
  313.  
  314.         //------------------------------------------------------------
  315.         // Get morpheme node, specified by index, from morpheme node list
  316.         //
  317.         err = AEGetNthDesc( &morphemeNodeList, morphemeIndex, typeAERecord, &theAEKeyword, &morpheme);
  318.         nrequire( err, getMorphemeNode_Failure);
  319.  
  320.         //------------------------------------------------------------
  321.         // Get homograph list from morpheme node
  322.         //
  323.         err = AEGetKeyDesc( &morpheme, keyAELAHomograph, typeAEList, &homographList);
  324.         AEDisposeDesc( &morpheme);
  325.         nrequire( err, getHomographList_Failure);
  326.         
  327.         //------------------------------------------------------------------------------
  328.         // Get 1st homograph node from homograph list
  329.         //
  330.         err = AEGetNthDesc( &homographList, 1, typeAERecord, &theAEKeyword, &homograph);
  331.         AEDisposeDesc( &homographList);
  332.         nrequire( err, getHomographNode_Failure);
  333.         
  334.         //------------------------------------------------------------------------------
  335.         // Get data size of homograph text, and checks overflow
  336.         //
  337.         err = AESizeOfKeyDesc( &homograph, keyAEText, &typeCode, &actualSize);
  338.         nrequire( err, getHomographDataSize_Failure);
  339.         
  340.         //
  341.         // Even if the buffer is overflowed, the actual total text size should be returned
  342.         //
  343.         totalLength += actualSize;
  344.  
  345.         if ( !hasOverflow)
  346.         {
  347.             long    tempMaxSize = actualSize;
  348.             
  349.             if ( totalLength > (long)maxLength)
  350.             {
  351.                 hasOverflow = true;
  352.                 tempMaxSize = (long)maxLength - ( totalLength - actualSize);
  353.             }
  354.             
  355.             //------------------------------------------------------------------------------
  356.             // Get converted string from homograph node, and adds it to the end of buffer
  357.             //
  358.             err = AEGetKeyPtr( &homograph, keyAEText, typeChar, &typeCode, outTextPtr,
  359.                                tempMaxSize, &actualSize);
  360.             nrequire( err, getHomographData_Failure);
  361.             
  362.             outTextPtr += tempMaxSize;
  363.         }
  364.         
  365.         AEDisposeDesc( &homograph);
  366.     }
  367.  
  368.     AEDisposeDesc( &morphemeNodeList);
  369.     AEDisposeDesc( &morphemeIndexList);
  370.     
  371.     *outLength = (ByteCount)totalLength;
  372.  
  373.     return noErr;
  374.  
  375. //'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  376. getHomographData_Failure:
  377. getHomographDataSize_Failure:
  378.     AEDisposeDesc( &homograph);
  379. getHomographNode_Failure:
  380. getHomographList_Failure:
  381. getMorphemeNode_Failure:
  382. getMorphemeIndex_Failure:
  383. countMorphemeNum_Failure:
  384.     AEDisposeDesc( &morphemeIndexList);
  385. getMorphemeIndexList_failure:
  386. getMorphemePath_failure:
  387. getMorphemePathList_failure:
  388.     AEDisposeDesc( &morphemeNodeList);
  389. getMorphemeNodeList_failure:
  390.     return err;
  391. }
  392.  
  393.  
  394. /* =======================================================================================
  395.     Routine:    MapErrorCode
  396.     
  397.     Purpose:    Maps internal error code to external one
  398.     
  399.     Params:        originalError (in)        : original (internal) error code
  400.    ======================================================================================= */
  401. static OSStatus
  402. MapErrorCode( OSStatus originalError )
  403. {
  404.     OSStatus    resultError;
  405.     
  406.     switch ( originalError)
  407.     {
  408.     case laFailAnalysisErr:
  409.         resultError = kConvFailAnalysisErr;
  410.         break;
  411.     
  412.     case laTextOverFlowErr:
  413.         resultError = kConvTextOverFlowErr;
  414.         break;
  415.         
  416.     case fnfErr:
  417.     case dcmBadDictionaryErr:
  418.     case dcmNotDictionaryErr:
  419.         resultError = kConvDictionaryNotFoundErr;
  420.         break;
  421.     
  422.     default:
  423.         resultError = originalError;
  424.         break;
  425.     }
  426.     
  427.     return resultError;
  428. }
  429.  
  430.  
  431.  
  432.  
  433.